using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Data;
using System.Globalization;
using System.Linq;
using T.FAS.Runtime.Base.Common;
using T.FAS.Runtime.Base.Dao;
using T.FAS.Runtime.Base.Entity;
using T.FAS.Runtime.Base.Service;
using T.FAS.Runtime.Base.SGSPI;

namespace T.FAS.Runtime.Base.SGPlugin
{
    public class DataChangeLogSGService : IDataChangeLogService
    {
        readonly ChangeLogBillSplitDao billSplitDao = new ChangeLogBillSplitDao();
        readonly ChangeLogDao changelogDao = new ChangeLogDao();
        readonly ChangeLogDetailDao changelogDetailDao = new ChangeLogDetailDao();
        public SGRetListData<DataChangeLogView> QueryDataChangeLog(string filter)
        {
            try
            {
                var queryFilter = JsonConvert.DeserializeObject<DataChangeLogQueryFilter>(filter);
                if (string.IsNullOrEmpty(queryFilter.BillID))
                {
                    throw new FasException(BaseExceptionCode.DataChangeLogQueryError, $"{T.ServiceComponent.I18N.Service.TermService.Current.GetText("T_FAS_fasr_Base_1423659048", "数据执行日志查询未指定单据BillID信息")}");
                }
                List<DataChangeLogView> logs;
                if (ConfigUtil.Instance.LogType == "BIGDATA")
                {
                    logs = GetDataChangeLogsFromES(queryFilter);
                }
                else if (ConfigUtil.Instance.LogType == "SplitTable")
                {
                    logs = GetDataChangeLogsFromSplitTable(queryFilter);
                }
                else
                {
                    logs = GetDataChangeLogsFromDB(queryFilter);
                }

                return new SGRetListData<DataChangeLogView>(logs.Count, logs);
            }
            catch (Exception ex)
            {
                throw new FasException(BaseExceptionCode.DataChangeLogQueryError, $"{T.ServiceComponent.I18N.Service.TermService.Current.GetText("T_FAS_fasr_Base_1773002242", "执行数据变更记录查询失败")}", ex);
            }
        }
        /// <summary>
        /// 从分表读取
        /// </summary>
        /// <param name="filter"></param>
        /// <returns></returns>
        private List<DataChangeLogView> GetDataChangeLogsFromSplitTable(DataChangeLogQueryFilter filter)
        {
            var list = new List<DataChangeLogView>();
            try
            {
                var billSplit = billSplitDao.GetObject(filter.BillID);
                List<ChangeLog> result;
                List<ChangeLogDetail> changelogDetails;
                if (!string.IsNullOrEmpty(billSplit?.TableNameSuf))
                {
                    result = changelogDao.GetBillSplitLogs(filter.BillID, filter.MetaDataCode, billSplit.TableNameSuf)
                        .OrderByDescending(t => t.CreateTime).ToList();
                    changelogDetails = changelogDetailDao.GetBillSplitLogDetail(filter.BillID, billSplit.TableNameSuf);
                }
                else
                {
                    result = changelogDao.GetChangeLogs(filter.BillID, filter.MetaDataCode)
                        .OrderByDescending(t => t.CreateTime).ToList();
                    changelogDetails = changelogDetailDao.GetChangeLogDetails(filter.BillID);
                }
                foreach (var item in result)
                {
                    var actionName = Convert.ToString(item.Action);
                    var log = new DataChangeLogView()
                    {
                        ID = Guid.NewGuid().ToString(),
                        StateCode = item.NewStateCode,
                        StateName = item.NewStateName,
                        ChangeUser = item.UserName,
                        ChangeUserID = item.UserID
                    };
                    List<ChangeLogDetail> changeDatas = changelogDetails.Where(t => t.ChangeLogID == item.ID).ToList();

                    log.DataChangeContent = changeDatas.OrderBy(t => t.SortOrder);
                    log.ChangeDateTime = item.CreateTime;
                    var oldStateName = item.OldStateName;
                    ChangeDesc(actionName, log, oldStateName);
                    list.Add(log);
                }
            }
            catch (Exception ex)
            {
                throw new FasException(BaseExceptionCode.DataChangeLogQueryError, $"{T.ServiceComponent.I18N.Service.TermService.Current.GetText("T_FAS_fasr_Base_533761435", "数据执行日志查询异常")}", ex);
            }

            return list;
        }
        /// <summary>
        /// 从数据库读取
        /// </summary>
        /// <param name="filter"></param>
        /// <returns></returns>
        private List<DataChangeLogView> GetDataChangeLogsFromDB(DataChangeLogQueryFilter filter)
        {
            var list = new List<DataChangeLogView>();
            try
            {
                List<ChangeLog> result;
                List<ChangeLogDetail> changelogDetails;

                result = changelogDao.GetChangeLogs(filter.BillID, filter.MetaDataCode)
                    .OrderByDescending(t => t.CreateTime).ToList();
                changelogDetails = changelogDetailDao.GetChangeLogDetails(filter.BillID);
                foreach (var item in result)
                {
                    var actionName = Convert.ToString(item.Action);
                    var log = new DataChangeLogView()
                    {
                        ID = Guid.NewGuid().ToString(),
                        StateCode = item.NewStateCode,
                        StateName = item.NewStateName,
                        ChangeUser = item.UserName,
                        ChangeUserID = item.UserID
                    };
                    List<ChangeLogDetail> changeDatas = changelogDetails.Where(t => t.ChangeLogID == item.ID).ToList();

                    log.DataChangeContent = changeDatas.OrderBy(t => t.SortOrder);
                    log.ChangeDateTime = item.CreateTime;
                    var oldStateName = item.OldStateName;
                    ChangeDesc(actionName, log, oldStateName);
                    list.Add(log);
                }
            }
            catch (Exception ex)
            {
                throw new FasException(BaseExceptionCode.DataChangeLogQueryError, $"{T.ServiceComponent.I18N.Service.TermService.Current.GetText("T_FAS_fasr_Base_533761435", "数据执行日志查询异常")}", ex);
            }

            return list;
        }
        /// <summary>
        /// 从大数据读取
        /// </summary>
        /// <param name="filter"></param>
        /// <returns></returns>
        private List<DataChangeLogView> GetDataChangeLogsFromES(DataChangeLogQueryFilter filter)
        {
            try
            {
                var selectSql = $"select Action,Datas,RowKeys,ServerIP,DataKey,BillID,AppCode,FuncID,ModuleCode,ClientIP,Ext11,Ext12,Ext13,Ext14,Ext15,Ext16,Ext17,Ext18,Ext19,Ext20,UserID,CreateTime from DataChangeLog where BillID='{filter.BillID}' and Ext17='{filter.MetaDataCode}' order by CreateTime desc Limit 1000";
                /* Todo
                IBDPDatabase bDPDatabase = BDPDatabaseHelper.GetBDPDatabase(BDPDacConst.ESLOG2, BDPDbType.ES);
                var context = new ESContext();
                var result = bDPDatabase.GetDataSet(selectSql, context);
                return ConverToDataChangeLogView(result);
                */
                return new List<DataChangeLogView>();
            }
            catch (Exception ex)
            {
                throw new FasException(BaseExceptionCode.DataChangeLogQueryError, $"{T.ServiceComponent.I18N.Service.TermService.Current.GetText("T_FAS_fasr_Base_533761435", "数据执行日志查询异常")}", ex);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name = "ds"></param>
        /// <returns>
        /// BillID:单据ID
        /// Action:Create|Update|Delete
        /// UserID:UserID
        /// CreateTime:LastModifyTime
        /// Ext11:OldStateCode
        /// Ext12:OldStateName
        /// Ext13:NewStateCode
        /// Ext14:NewStateName
        /// Ext15:CDOID
        /// Ext16:TenantID
        /// Ext17:CDOCode
        /// Ext18:CDOName
        /// Ext19:UserName
        /// Ext20:当CreateTime为空时，备用最后修改时间字段
        /// Datas:Content
        /// </returns>
        private List<DataChangeLogView> ConverToDataChangeLogView(DataSet ds)
        {
            var list = new List<DataChangeLogView>();
            if (ds != null && ds.Tables != null && ds.Tables.Count > 0 && ds.Tables[0].Rows != null)
            {
                foreach (DataRow row in ds.Tables[0].Rows)
                {
                    var actionName = Convert.ToString(row["Action"]);
                    var log = new DataChangeLogView()
                    { ID = Guid.NewGuid().ToString(), StateCode = Convert.ToString(row["Ext13"]), StateName = Convert.ToString(row["Ext14"]), ChangeUser = Convert.ToString(row["Ext19"]), ChangeUserID = Convert.ToString(row["UserID"]), DataChangeContent = JsonConvert.DeserializeObject<JArray>(Convert.ToString(row["Datas"])), };
                    var changeDateTimeStr = Convert.ToString(row["CreateTime"]);
                    if (string.IsNullOrEmpty(changeDateTimeStr))
                    {
                        changeDateTimeStr = Convert.ToString(row["Ext20"]);
                    }

                    log.ChangeDateTime = ConvertToDateTime(changeDateTimeStr);
                    var oldStateName = Convert.ToString(row["Ext12"]);
                    ChangeDesc(actionName, log, oldStateName);

                    list.Add(log);
                }
            }

            return list;
        }

        private static void ChangeDesc(string actionName, DataChangeLogView log, string oldStateName)
        {
            //如果当前状态字段为空，说明没有变更状态字段
            if (string.IsNullOrEmpty(Convert.ToString(log.StateName)))
            {
                if (actionName.Equals("create", StringComparison.OrdinalIgnoreCase))
                {
                    log.Description = $"{T.ServiceComponent.I18N.Service.TermService.Current.GetText("T_FAS_fasr_Base_721696260", $"新增了数据")}";
                }
                else if (actionName.Equals("Update", StringComparison.OrdinalIgnoreCase))
                {
                    log.Description = $"{T.ServiceComponent.I18N.Service.TermService.Current.GetText("T_FAS_fasr_Base_1936206254", $"修改了数据")}";
                }
                else if (actionName.Equals("delete", StringComparison.OrdinalIgnoreCase))
                {
                    log.Description = $"{T.ServiceComponent.I18N.Service.TermService.Current.GetText("T_FAS_fasr_Base_506381513", $"删除了数据")}";
                }
                else
                    log.Description = $"{T.ServiceComponent.I18N.Service.TermService.Current.GetText("T_FAS_fasr_Base_750100379", $"修改了内容")}";
            }
            else
            {
                if (string.IsNullOrEmpty(oldStateName))
                {
                    log.Description = $"{T.ServiceComponent.I18N.Service.TermService.Current.GetTextFormatted("T_FAS_fasr_Base_377345939", "状态初始化为{0}", log.StateName)}";
                }
                else
                {
                    log.Description = $"{T.ServiceComponent.I18N.Service.TermService.Current.GetTextFormatted("T_FAS_fasr_Base_22887384", "将{0}状态变更为{1}", oldStateName, log.StateName)}";
                }
            }
        }

        private DateTime ConvertToDateTime(string time)
        {
            if (string.IsNullOrEmpty(time))
                return DateTime.Now;
            try
            {
                var dFormat = "yyyyMMddHHmmssfff";
                if (time.Length.Equals(19))
                {
                    dFormat = "yyyyMMddHHmmss";
                }

                var dateTime = DateTime.ParseExact(time.Substring(0, time.Length - 5), dFormat, new System.Globalization.CultureInfo("zh-CN"), System.Globalization.DateTimeStyles.AllowWhiteSpaces);
                return dateTime;
            }
            catch (Exception ex)
            {
                return DateTime.Now;
            }
        }
        private void UpdateDataChangeLog(UnitTestCDO cdo, List<DataChangeLogView> logs, string billID)
        {
            var list = new List<DataChangeDetail>();
            var changeColumns = cdo.Columns.FindAll(x => x.IsDataChange);
            if (changeColumns.Count > 0)
            {
                var log = new DataChangeLogView()
                {ID = Guid.NewGuid().ToString(), ChangeDateTime = DateTime.Now, ChangeUser = cdo.GetLastModifier(), };
                var stateColumn = changeColumns.Find(x => x.IsStateColumn);
                if (stateColumn == null)
                {
                    log.StateCode = "";
                    log.StateName = "";
                    log.Description = $"{T.ServiceComponent.I18N.Service.TermService.Current.GetText("T_FAS_fasr_Base_750100379", $"修改了内容")}";
                }
                else
                {
                    log.StateCode = cdo.GetStateCode();
                    log.StateName = cdo.GetStateName();
                    log.Description = $"{T.ServiceComponent.I18N.Service.TermService.Current.GetTextFormatted("T_FAS_fasr_Base_289090245", "将{0}",cdo.GetStateChangeContent())}";
                }

                changeColumns.ForEach(c =>
                {
                    list.Add(new DataChangeDetail()
                    {BillID = billID, MetaDataType = "CDO", MetadataID = cdo.MetaDataID, MetaDataCode = cdo.MetaDataCode, MetaDataName = cdo.MetaDataName, ColumnID = c.ColumnID, ColumnCode = c.ColumnCode, ColumnName = c.ColumnName, OldData = c.OldValue, NewData = c.Newvalue, });
                }

                );
                log.DataChangeContent = list;
                logs.Add(log);
            }

            cdo.SubmitData();
        }

        private UnitTestCDO InitDemoData()
        {
            var cdo = new UnitTestCDO()
            {
                MetaDataID = Guid.NewGuid().ToString(),
                MetaDataCode = "CDO_TestCase",
                MetaDataName = "CDO_测试用例",
            };
            cdo.Columns = new List<UnitTestCDOColumn>();
            cdo.Columns.Add(new UnitTestCDOColumn()
            {
                ColumnID = Guid.NewGuid().ToString(),
                ColumnCode = "ID",
                ColumnName = "标识",
                IsStateColumn = false,
                OldValue = "",
                Newvalue = Guid.NewGuid().ToString(),
                IsDataChange = true
            });
            cdo.Columns.Add(new UnitTestCDOColumn()
            {
                ColumnID = Guid.NewGuid().ToString(),
                ColumnCode = "Code",
                ColumnName = "编号",
                IsStateColumn = false,
                OldValue = "",
                Newvalue = "Code:" + DateTime.Now.ToString(),
                IsDataChange = true,
            });
            cdo.Columns.Add(new UnitTestCDOColumn()
            {
                ColumnID = Guid.NewGuid().ToString(),
                ColumnCode = "Name",
                ColumnName = "名称",
                IsStateColumn = false,
                OldValue = "",
                Newvalue = "Name:" + Guid.NewGuid().ToString(),
                IsDataChange = true,
            });
            cdo.Columns.Add(new UnitTestCDOColumn()
            {
                ColumnID = Guid.NewGuid().ToString(),
                ColumnCode = "Description",
                ColumnName = "描述",
                IsStateColumn = false,
                OldValue = "",
                Newvalue = "描述信息:" + DateTime.Now.ToString(),
                IsDataChange = true,
            });
            cdo.Columns.Add(new UnitTestCDOColumn()
            {
                ColumnID = Guid.NewGuid().ToString(),
                ColumnCode = "LastModifier",
                ColumnName = "最后修改人",
                IsStateColumn = false,
                IsUserColumn = true,
                OldValue = "",
                Newvalue = "Sys",
                IsDataChange = true
            });
            cdo.Columns.Add(new UnitTestCDOColumn()
            {
                ColumnID = Guid.NewGuid().ToString(),
                ColumnCode = "LastModifyTime",
                ColumnName = "最后修改时间",
                IsStateColumn = false,
                IsUserColumn = false,
                OldValue = "",
                Newvalue = DateTime.Now,
                IsDataChange = true
            });
            cdo.Columns.Add(new UnitTestCDOColumn()
            {
                ColumnID = Guid.NewGuid().ToString(),
                ColumnCode = "Status",
                ColumnName = "状态",
                IsStateColumn = true,
                OldValue = "",
                Newvalue = BillState.New,
                IsDataChange = true,
            });
            return cdo;
        }


        public enum BillState
        {
            /// <summary>
            /// 新建
            /// </summary>
            New,
            /// <summary>
            /// 已接收
            /// </summary>
            Received,
            /// <summary>
            /// 处理中
            /// </summary>
            Processing,
            /// <summary>
            /// 已解决
            /// </summary>
            Resolved,
            /// <summary>
            /// 已关闭
            /// </summary>
            Closed,
            /// <summary>
            /// 未解决
            /// </summary>
            UnResolved
        }

        [Serializable]
        public class DataChangeDetail
        {
            public string MetaDataType
            {
                get;
                set;
            }

            public string MetadataID
            {
                get;
                set;
            }

            public string MetaDataCode
            {
                get;
                set;
            }

            public string MetaDataName
            {
                get;
                set;
            }
            public string ColumnID
            {
                get;
                set;
            }

            public string ColumnCode
            {
                get;
                set;
            }

            public string ColumnName
            {
                get;
                set;
            }

            public object OldData
            {
                get;
                set;
            }

            public object NewData
            {
                get;
                set;
            }

            public string BillID
            {
                get;
                set;
            }
        }

        [Serializable]
        public class UnitTestCDO
        {
            public string MetaDataID
            {
                get;
                set;
            }

            public string MetaDataCode
            {
                get;
                set;
            }

            public string MetaDataName
            {
                get;
                set;
            }

            public List<UnitTestCDOColumn> Columns
            {
                get;
                set;
            }

            public string GetLastModifier()
            {
                if (Columns != null)
                {
                    var user = Columns.Find(x => x.IsUserColumn);
                    if (user != null)
                    {
                        if (!string.IsNullOrEmpty(Convert.ToString(user.Newvalue)))
                            return Convert.ToString(user.Newvalue);
                        else
                            return Convert.ToString(user.OldValue);
                    }
                }

                return "Sys";
            }

            public int GetStateCode()
            {
                if (Columns != null)
                {
                    var state = Columns.Find(x => x.IsStateColumn);
                    if (state != null)
                    {
                        if (state.Newvalue != null)
                            return Convert.ToInt32(state.Newvalue as BillState? );
                        else
                            return Convert.ToInt16(state.OldValue as BillState? );
                    }
                }

                return -1;
            }

            public string GetStateName()
            {
                if (Columns != null)
                {
                    var state = Columns.Find(x => x.IsStateColumn);
                    if (state != null)
                    {
                        if (state.Newvalue != null)
                            return Convert.ToString(state.Newvalue as BillState? );
                        else
                            return Convert.ToString(state.OldValue as BillState? );
                    }
                }

                return "";
            }

            public string GetStateChangeContent()
            {
                if (Columns != null)
                {
                    var state = Columns.Find(x => x.IsStateColumn);
                    if (state != null && state.Newvalue != null)
                    {
                         return $"{T.ServiceComponent.I18N.Service.TermService.Current.GetTextFormatted("T_FAS_fasr_Base_1859035235", "{0}状态变更为{1}", state.OldValue, state.Newvalue)}";
                    }
                }

                return "";
            }

            public void SubmitData()
            {
                if (Columns != null && Columns.Count > 0)
                {
                    Columns.ForEach(x => x.SubmitData());
                }
            }

            public void SetColumnValue(string columnCode, object value)
            {
                var col = Columns.Find(x => x.ColumnCode.Equals(columnCode, StringComparison.OrdinalIgnoreCase));
                if (col != null)
                {
                    col.SetValue(value);
                }
            }
        }

        [Serializable]
        public class UnitTestCDOColumn
        {
            public string ColumnID
            {
                get;
                set;
            }

            public string ColumnCode
            {
                get;
                set;
            }

            public string ColumnName
            {
                get;
                set;
            }

            public object OldValue
            {
                get;
                set;
            }

            public object Newvalue
            {
                get;
                set;
            }

            public bool IsDataChange
            {
                get;
                set;
            }

            public bool IsStateColumn
            {
                get;
                set;
            }

            public bool IsUserColumn
            {
                get;
                set;
            }

            public void SubmitData()
            {
                this.OldValue = this.Newvalue;
                this.IsDataChange = false;
            }

            public void SetValue(object data)
            {
                this.Newvalue = data;
                this.IsDataChange = true;
            }
        }
    }
}